using System;
using System.Globalization;
using NUnit.Framework;
using ValidationFramework.Reflection;

namespace ValidationFramework.Tests
{

	public class NumberConversionRuleTest
	{
		const string expectedErrorMessage = "expectedErrorMessage";
		const string expectedRuleSet = "EXPECTEDRULESET";
		private const TypeCode expectedTypeCode = TypeCode.Int32;
		const NumberStyles expectedNumberStyles = NumberStyles.Integer;

		[TestFixture]
		public class Contruction
		{
			[Test]
			public void AllParams()
			{
				var rule = new NumberConversionRule(expectedErrorMessage, false, expectedTypeCode, NumberFormatInfo.InvariantInfo, false, expectedNumberStyles);
				Assert.AreEqual(expectedTypeCode, rule.TypeCode);
				Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
				Assert.AreEqual(expectedNumberStyles, rule.NumberStyles);
				Assert.IsFalse(rule.UseErrorMessageProvider);
			}




			[Test]
			[ExpectedException(typeof(ArgumentException))]
			public void ExceptionStringTypeCode()
			{
				new NumberConversionRule(expectedErrorMessage, false, TypeCode.String, null, false, null);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException))]
			public void ExceptionDateTimeTypeCode()
			{
				new NumberConversionRule(expectedErrorMessage, false, TypeCode.DateTime, null, false, null);
			}


		}

		[TestFixture]
		public class IsEquivalent
		{

			[Test]
			public void TypeCodeCompare()
			{
				var rule1 = new NumberConversionRule(null, false, TypeCode.Int32, null, false, null);
				var rule2 = new NumberConversionRule(null, false, TypeCode.Int32, null, false, null);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new NumberConversionRule(null, false, TypeCode.Int32, null, false, null);
				rule2 = new NumberConversionRule(null, false, TypeCode.Decimal, null, false, null);
				Assert.IsFalse(rule1.IsEquivalent(rule2));
			}

			[Test]
			public void NumberFormatInfoCompare()
			{
				var rule1 = new NumberConversionRule(null, false, TypeCode.Int32, NumberFormatInfo.InvariantInfo, false, null);
				var rule2 = new NumberConversionRule(null, false, TypeCode.Int32, NumberFormatInfo.InvariantInfo, false, null);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new NumberConversionRule(null, false, TypeCode.Int32, NumberFormatInfo.InvariantInfo, false, null);
				rule2 = new NumberConversionRule(null, false, TypeCode.Int32, NumberFormatInfo.CurrentInfo, false, null);
				Assert.IsFalse(rule1.IsEquivalent(rule2));
			}

			[Test]
			public void NumberStylesCompare()
			{
				var rule1 = new NumberConversionRule(null, false, TypeCode.Int32, null, false, NumberStyles.Any);
				var rule2 = new NumberConversionRule(null, false, TypeCode.Int32, null, false, NumberStyles.Any);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new NumberConversionRule(null, false, TypeCode.Int32, null, false, NumberStyles.Any);
				rule2 = new NumberConversionRule(null, false, TypeCode.Int32, null, false, NumberStyles.Integer);
				Assert.IsFalse(rule1.IsEquivalent(rule2));
			}
		}



		[TestFixture]
		public class RuleInterpretation
		{
			[Test]
			public void Simple()
			{
				var nullableRule = new NumberConversionRule(null, false, TypeCode.Int32, null, false, null);
				Assert.IsNotNull(nullableRule.RuleInterpretation);

			}
		}

		[TestFixture]
		public class Validate
		{

			[Test]
			public void Simple()
			{
				var nullableRule = new NumberConversionRule(null, false, TypeCode.Decimal, null, true, null);

				Assert.IsNull(nullableRule.Validate(null, null, null, null));
				Assert.IsNull(nullableRule.Validate(null, string.Empty, null, null));
				Assert.IsNotNull(nullableRule.Validate(null, "sdf", null, null));
				Assert.IsNull(nullableRule.Validate(null, "1.2 2", null, null));
				Assert.IsNull(nullableRule.Validate(null, "1 2", null, null));

			}

		}

		[TestFixture]
		public class CheckTypes
		{


			[Test]
			public void Simple()
			{
			    var rule = new NumberConversionRule(null, false, TypeCode.Int32, null, false, null);
			    rule.CheckType(new MockInfoDescriptor(TypePointers.StringTypeHandle, "foo"));
			}


		    [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Member 'foo' must be a 'System.String' to be used for the ValidationFramework.NumberConversionRule. Actual Type 'System.Int32'.\r\nParameter name: value")]
            public void ExceptionIncorrectType()
            {
		        var rule = new NumberConversionRule(null, false, TypeCode.Int32, null, false, null);
		        rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
            }
		}

	}
}